package gbench.common.matlib.matrix;

import gbench.common.matlib.MatlibCanvas.Seq;
import gbench.common.matlib.MatlibCanvas.XVec;
import gbench.common.matlib.rdd.BasePair;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Stream;

/**
 * T类型的数据矩阵
 *
 * @author gbench
 */
public class Matrix<T> extends XXVec<T, Matrix<T>> {

    /**
     * 生成矩阵对象
     *
     * @param data 矩阵对象
     */
    public Matrix(final XVec<XVec<T>> data) {
        super(data);
    }

    /**
     * 生成矩阵对象
     *
     * @param data 矩阵对象
     */
    public Matrix(final List<XVec<T>> data) {
        super(XVec.OF(data));
    }

    /**
     * 数据矩阵数据
     *
     * @param m    行数
     * @param n    列数
     * @param data 数据矩阵
     * @return 数据矩阵数据
     */
    @SafeVarargs
    public Matrix(final int m, final int n, final T... data) {
        this(XXVec.OF(m, n, data));
    }

    /**
     * 换药不换瓶 映射
     * 
     * @param <U>    元素类型
     * @param mapper 数据映射
     * @return U类型的结果矩阵
     */
    public <U> Matrix<U> fmap(final Function<T, U> mapper) {
        return this.fmap(mapper, Matrix::new);
    }

    /**
     * 换药不换瓶 映射
     * 
     * @param <U> 元素类型 mapper 数据映射:(bp:(行索引:从0开始,列索引从0开始),t:数据元素)->u,
     * @return U类型的结果矩阵
     */
    public <U> Matrix<U> fmap(final BiFunction<BasePair<Long, Long>, T, U> mapper) {
        return this.fmap(mapper, Matrix::new);
    }

    /**
     * 构造一个复制品
     *
     * @param data 矩阵数据
     * @return SELF 数据
     */
    public Matrix<T> duplicate(final T[][] data) {
        return new Matrix<>(XVec.OF(data).fmap((Function<T[], XVec<T>>) XVec::OF));
    }

    /**
     * 生成T类型的数据矩阵(行顺序填满)
     * 
     * @param m         行数
     * @param n         列数
     * @param generator 矩阵元素生成器,(i:行号索引从0开始,j:列号索引从0开始)->c
     * @return T类型的数据矩阵
     */
    public static <T> Matrix<T> of(final int m, final int n, final BiFunction<Integer, Integer, T> generator) {
        return XXVec.OF(m, n, generator).mutateX(Matrix::new);
    }

    /**
     * 生成T类型的数据矩阵(行顺序填满)
     * 
     * @param m   行数
     * @param n   列数
     * @param seq 列元素序列
     * @return T类型的数据矩阵
     */
    public static <T> Matrix<T> of(final int m, final int n, final Seq<T> seq) {
        return Matrix.of(m, n, (i, j) -> seq.mget(j * n + i));
    }

    /**
     * 生成T类型的数据矩阵(行顺序填满)
     * 
     * @param m   行数
     * @param n   列数
     * @param seq 列顺序元素序列
     * @return T类型的数据矩阵
     */
    public static <T> Matrix<T> ofrows(final int m, final int n, final Seq<T> seq) {
        return Matrix.of(m, n, (i, j) -> seq.mget(i * m + j));
    }

    /**
     * 生成T类型的数据矩阵(行顺序填满)
     * 
     * @param m         行数
     * @param n         列数
     * @param generator 矩阵元素生成器,(i:行号索引从0开始,j:列号索引从0开始)->c
     * @return T类型的数据矩阵
     */
    public static <T> Matrix<T> mxn(final int m, final int n, final BiFunction<Integer, Integer, T> generator) {
        return XXVec.OF(m, n, generator).mutateX(Matrix::new);
    }

    /**
     * 行顺序<br>
     * T类型元素的矩阵归集器,seq2mxclc 的别名
     * 
     * @param <T> 元素类型
     * @return T类型元素的矩阵归集器
     */
    public static <T> Collector<Seq<T>, ?, Matrix<T>> mxclc() {
        return seq2mxclc(false);
    }

    /**
     * 行顺序<br>
     * T类型元素的矩阵归集器,seq2mxclc 的别名
     * 
     * @param <T> 元素类型
     * @param transpose 是否对矩阵进行转置,true 转置,false 维持原样
     * @return T类型元素的矩阵归集器
     */
    public static <T> Collector<Seq<T>, ?, Matrix<T>> mxclc(final boolean transpose) {
        return seq2mxclc(transpose);
    }

    /**
     * 行顺序<br>
     * T类型元素的矩阵归集器
     * 
     * @param <T>       元素类型
     * @param transpose 是否对矩阵进行转置,true 转置,false 维持原样
     * @return T类型元素的矩阵归集器
     */
    @SuppressWarnings("unchecked")
    public static <T, U extends Seq<T>> Collector<U, ?, Matrix<T>> seq2mxclc(final boolean transpose) {
        return Collector.of(() -> new ArrayList<XVec<T>>(), (aa, a) -> {
            if (a instanceof XVec) { // 判断元素类型是否是XVec
                aa.add((XVec<T>) a);
            } else { // 其他Seq
                aa.add(XVec.OF(a.data()));
            } // if
        }, (aa, bb) -> {
            aa.addAll(bb);
            return aa;
        }, (e) -> {
            final var mm = new Matrix<T>(e);
            return transpose ? mm.transpose() : mm;
        });
    }

    /**
     * 行顺序<br>
     * T类型元素的矩阵归集器
     * 
     * @param <T>       元素类型
     * @param transpose 是否对矩阵进行转置,true 转置,false 维持原样
     * @return T类型元素的矩阵归集器
     */
    public static <T> Collector<T[], ?, Matrix<T>> aa2mxclc(final boolean transpose) {
        return Collector.of(() -> new ArrayList<XVec<T>>(), (aa, a) -> aa.add(XVec.OF(a)), (aa, bb) -> {
            aa.addAll(bb);
            return aa;
        }, (e) -> {
            final var mm = new Matrix<T>(e);
            return transpose ? mm.transpose() : mm;
        });
    }

    /**
     * 行顺序<br>
     * T类型元素的矩阵归集器
     * 
     * @param <T>       元素类型
     * @param transpose 是否对矩阵进行转置,true 转置,false 维持原样
     * @return T类型元素的矩阵归集器
     */
    public static <T> Collector<Collection<T>, ?, Matrix<T>> ll2mxclc(final boolean transpose) {
        return Collector.of(() -> new ArrayList<XVec<T>>(), (aa, a) -> aa.add(XVec.OF(a)), (aa, bb) -> {
            aa.addAll(bb);
            return aa;
        }, (e) -> {
            final var mm = new Matrix<T>(e);
            return transpose ? mm.transpose() : mm;
        });
    }

    /**
     * 行顺序<br>
     * T类型元素的矩阵归集器
     * 
     * @param <T>       元素类型
     * @param transpose 是否对矩阵进行转置,true 转置,false 维持原样
     * @return T类型元素的矩阵归集器
     */
    public static <T> Collector<Stream<T>, ?, Matrix<T>> ss2mxclc(final boolean transpose) {
        return Collector.of(() -> new ArrayList<XVec<T>>(), (aa, a) -> aa.add(XVec.OF(a)), (aa, bb) -> {
            aa.addAll(bb);
            return aa;
        }, (e) -> {
            final var mm = new Matrix<T>(e);
            return transpose ? mm.transpose() : mm;
        });
    }

}